package com.xiaoxiaoyu.framework.core;

import com.xiaoxiaoyu.framework.core.annoattion.Compenent;
import com.xiaoxiaoyu.framework.core.annoattion.Controller;
import com.xiaoxiaoyu.framework.core.annoattion.Repository;
import com.xiaoxiaoyu.framework.core.annoattion.Service;
import com.xiaoxiaoyu.util.ClassUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @program: simple-Spring
 * @description: 容器类
 * @author: 小小鱼
 * @date: 2021-01-28 13:28
 **/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanContainer<T> {

    //bean容器集合
    private final ConcurrentHashMap<Class<?>,Object> beans=new ConcurrentHashMap<>();

    //bean注解集合
    private final List<Class<? extends Annotation>> BEAN_ANNOTATION= Arrays.asList(Compenent.class, Controller.class, Service.class, Repository.class
            );
    public static BeanContainer getInstance(){
        return containerHolder.HOLDER.beanContainer;
    }

    //利用枚举创建可以抵御反射机制的单列
    private enum containerHolder{
        HOLDER;

        private BeanContainer beanContainer;

        containerHolder(){
            beanContainer=new BeanContainer();
        }

    }

    //判断容器是否被加载过
    private  Boolean loader=false;

    //当前容器中的class个数
    private Integer size=beans.size();

    public Boolean isLoader(){
        return loader;
    }

    public Integer getSize(){
        return size;
    }


    public synchronized void loaderBeans(String packageName){
        if(loader){
            log.info("当前beanFactory已经初始化过了！");
            return;
        }
        Set<Class<?>> classSet = ClassUtil.gainPackageClass(packageName);
        if(classSet.isEmpty()){
            log.info("{}:不存在class");
            return;
        }
        for (Class<?> targetClass : classSet) {
            for (Class<? extends Annotation> clazz : BEAN_ANNOTATION) {
                if(targetClass.isAnnotationPresent(clazz)){
                    beans.put(targetClass,ClassUtil.newInstance(targetClass,true));
                }
            }
        }
        loader=true;
    }

    /**
     * 添加一个class对象及其Bean实例
     *
     * @param clazz Class对象
     * @param bean  Bean实例
     * @return 原有的Bean实例, 没有则返回null
     */
    public Object addBean(Class<?> clazz, Object bean) {
        return beans.put(clazz, bean);
    }

    /**
     * 移除一个IOC容器管理的对象
     *
     * @param clazz Class对象
     * @return 删除的Bean实例, 没有则返回null
     */
    public Object removeBean(Class<?> clazz) {
        return beans.remove(clazz);
    }

    /**
     * 根据Class对象获取Bean实例
     *
     * @param clazz Class对象
     * @return Bean实例
     */
    public Object getBean(Class<?> clazz) {
        return beans.get(clazz);
    }

    /**
     * 获取容器管理的所有Class对象集合
     *
     * @return Class集合
     */
    public Set<Class<?>> getClasses(){
        return beans.keySet();
    }


    /**
     * 获取所有Bean集合
     *
     * @return Bean集合
     */
    public Set<Object> getBeans(){
        return new HashSet<>(beans.values());
    }

    /**
     * 根据注解筛选出Bean的Class集合
     *
     * @param annotation 注解
     * @return Class集合
     */
    public Set<Class<?>> getClassesByAnnotation(Class<? extends Annotation> annotation){
        //1.获取beans的所有class对象
        Set<Class<?>> keySet = getClasses();
        if(keySet.isEmpty()){
            log.warn("nothing in beans");
            return null;
        }
        //2.通过注解筛选被注解标记的class对象，并添加到classSet里
        Set<Class<?>> classSet = new HashSet<>();
        for(Class<?> clazz : keySet){
            //类是否有相关的注解标记
            if(clazz.isAnnotationPresent(annotation)){
                classSet.add(clazz);
            }
        }
        return classSet.size() > 0? classSet: null;
    }

    /**
     * 通过接口或者父类获取实现类或者子类的Class集合，不包括其本身
     *
     * @param interfaceOrClass 接口Class或者父类Class
     * @return Class集合
     */
    public Set<Class<?>> getClassesBySuper(Class<?> interfaceOrClass){
        //1.获取beans的所有class对象
        Set<Class<?>> keySet = getClasses();
        if(keySet.isEmpty()){
            log.warn("nothing in beans");
            return null;
        }
        //2.判断keySet里的元素是否是传入的接口或者类的子类，如果是，就将其添加到classSet里
        Set<Class<?>> classSet = new HashSet<>();
        for(Class<?> clazz : keySet){
            //判断keySet里的元素是否是传入的接口或者类的子类
            if(interfaceOrClass.isAssignableFrom(clazz) && !clazz.equals(interfaceOrClass)){
                classSet.add(clazz);
            }
        }
        return classSet.size() > 0? classSet: null;
    }












}
